#include "sdlengine.hpp"

using namespace sdl_engine;

class TestGui: public unit_test::Test, public App {
public:
    void SetUp() override {
        engine.SetApp(this);

        auto window = gui::CreateWindow(gui::ID_ANY,
                                        point(100, 50), size(480, 320),
                                        "window1",
                                        false);
        auto linearLayout_ = gui::CreateLinearLayout(gui::ID_ANY);
        window->SetLayout(linearLayout_);

        auto treelist = gui::CreateTreeList(gui::ID_ANY, "tree root");
        auto& root = treelist->GetRoot();
        auto& child1 = root.Append("child1");
        child1.Append("chile1_1");
        child1.Append("chile1_2").Append("child1_2_1");
        root.Append("child2");
        auto& child3 = root.Append("child3");
        root.expand = true;
        child3.Append("child3_1");
        child3.Append("child3_2");
        child3.Append("child3_3");
        child3.expand = false;
        treelist->SetClickNodeCb([](gui::TreeList::Node& node) {
            SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
                                     "node information",
                                     Fmt("node \"%s\" clicked", node.GetText().c_str()).c_str(),
                                     nullptr);
        });
        treelist->Pack();
        linearLayout_->AddWidget(treelist);

        auto button1_ = gui::CreateButton(gui::ID_ANY, "button1");
        linearLayout_->AddWidget(button1_);

        auto button2_ = gui::CreateButton(gui::ID_ANY, "button2");
        linearLayout_->AddWidget(button2_);
        button2_->SetClickCb([](gui::Widget*) { Logi("button2 clicked"); });

        auto label = gui::CreateLabel(gui::ID_ANY, "label1");
        linearLayout_->AddWidget(label);

        auto checkbox = gui::CreateCheckbox(gui::ID_ANY, "checkbox");
        linearLayout_->AddWidget(checkbox);

        auto inputbox = gui::CreateInputBox(gui::ID_ANY, 200);
        linearLayout_->AddWidget(inputbox);

        auto scrollbar1 = gui::CreateSlidebar(gui::ID_ANY, 0, 100, 0, 100);
        linearLayout_->AddWidget(scrollbar1);

        auto scrollbar2 = gui::CreateSlidebar(gui::ID_ANY, 0, 100, 0, 100, false);
        linearLayout_->AddWidget(scrollbar2);

        auto scrollbar3 = gui::CreateSlidebar(gui::ID_ANY, 0, 100, 0, 200);
        linearLayout_->AddWidget(scrollbar3);

        auto gridLayout = gui::CreateGridLayout(gui::ID_ANY, size(20, 20));

        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "0"), 0, 0);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "1"), 0, 1);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "2"), 0, 2);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "3"), 1, 0);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "4"), 1, 1);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "5"), 1, 2);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "6"), 2, 0);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "7"), 2, 1);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "8"), 2, 2);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "="), 3, 0, 1, 2);
        gridLayout->AddWidget(gui::CreateButton(gui::ID_ANY, "9"), 3, 2);

        linearLayout_->AddWidget(gridLayout);

        auto gridLayout2 = gui::CreateGridLayout(gui::ID_ANY, size(20, 20));

        gridLayout2->AddWidget(gui::CreateLabel(gui::ID_ANY, "姓名:"), 0, 0, 1, 2);
        gridLayout2->AddWidget(gui::CreateInputBox(gui::ID_ANY, 50), 0, 2, 1, 5);
        gridLayout2->AddWidget(gui::CreateLabel(gui::ID_ANY, "编号:"), 1, 0, 1, 2);
        gridLayout2->AddWidget(gui::CreateInputBox(gui::ID_ANY, 50), 1, 2, 1, 5);

        linearLayout_->AddWidget(gridLayout2);

        auto window2 = gui::CreateFoldWindow(gui::ID_ANY,
                                             point(0, 0),
                                             size(400, 300),
                                             "inner window");

        linearLayout_->AddWidget(window2);

        auto innerLayout = gui::CreateLinearLayout(gui::ID_ANY);

        window2->SetLayout(innerLayout);

        auto innerButton = gui::CreateButton(gui::ID_ANY, "inner button1");
        innerLayout->AddWidget(innerButton);

        auto innerLabel = gui::CreateLabel(gui::ID_ANY, "inner label");
        innerLayout->AddWidget(innerLabel);

        auto imageButton = gui::CreateImageButton(gui::ID_ANY, textureStock_.Create("assets/block.png"));
        innerLayout->AddWidget(imageButton);

        /* if you create a widget but don't add it to a containable widget,
         * it will show on screen directly. */
        mousePosLabel_ = gui::CreateLabel(gui::ID_ANY, "");
        mousePosLabel_->SetPosition(point(0, 0));

        if (engine.IsCanvaResizable()) {
            canvaOpenLabel_ = gui::CreateLabel(gui::ID_ANY, "finger position: None");
            canvaOpenLabel_->SetPosition(point(0, 25));
        }

        initAudio();

        engine.SetClearColor(color(100, 100, 100));
    }

    void OnMouseMotion(const EventMouseMotion& motion) override {
        mousePosLabel_->SetText(Fmt("Mouse Position:(%d, %d)",
                                    motion.Position().x,
                                    motion.Position().y));
    }

    void OnFingerMotion(const EventTouchFinger& finger) override {
        canvaOpenLabel_->SetText(Fmt("finger position:(%d, %d)",
                                 finger.GetPosition().x, finger.GetPosition().y));
    }

    void Render([[ maybe_unused ]] Renderer& renderer) override {
        gui::Render();

        // for debug
        gui::__PointOutFocuseWidget();
    }

    void Run() override {
        RUN_ENGINE();
    }

    void TearDown() override {
        SDL_FreeWAV(audioBuffer_);
        SDL_CloseAudio();
    }

private:
    gui::Label* mousePosLabel_ = nullptr;
    gui::Label* canvaOpenLabel_ = nullptr;
    Stock<Texture*> textureStock_;
    Uint8* audioBuffer_ = nullptr;
    Uint32 audioLen_ = 0;

    void initAudio() {
        SDL_AudioSpec wavSpec;
        if (SDL_LoadWAV("assets/explosion.wav", &wavSpec, &audioBuffer_, &audioLen_) == nullptr) {
            Logi(Fmt("load wave explosion.wav failed: %s", SDL_GetError()));
        }

        SDL_AudioSpec spec;
        spec.channels = 2;
        spec.format = AUDIO_S16;
        spec.samples = 1024;
        spec.freq = 22050;
        spec.userdata = audioBuffer_;
        spec.callback = [](void* udata, Uint8* stream, int len) {
            Uint8* audioBuffer = (Uint8*)udata;
            SDL_memset(stream, 0, len);
            if (len == 0)
                return;
            SDL_MixAudio(stream, audioBuffer, len, SDL_MIX_MAXVOLUME);
        };
        if (SDL_OpenAudio(&spec, nullptr) < 0) {
            Loge("open audio failed");
        }
        SDL_PauseAudio(0);
    }
};

int main(int argc, char** argv) {
    Window::CreateInfo createInfo;
    createInfo.SetSize(size(720, 480));
    createInfo.SetTitle("test GUI");

    AndroidInitInfo androidInfo;
    androidInfo.SetOrientations({AndroidInitInfo::Orientation::LANDSCAPE_LEFT})
               .SeperateMouseAndTouch();
    engine.Init(argc, argv, createInfo, Renderer::CreateInfo(), true, SDL_INIT_EVERYTHING, nullptr, &androidInfo);

    gui::Init(engine.GetRenderer(),
              engine.GetFontStock().Create("assets/SimHei.ttf", 20));
    Logi("gui init OK");

    auto test1 = new TestGui;

    unit_test::unittest.RegistTest(test1);
    unit_test::unittest.AddTest(test1);

    unit_test::unittest.RunTests();

    gui::Shutdown();
    engine.Shutdown();
    return 0;
}
